Practice questions

Answer the following questions:

  1. What is a key difference between area data and point data?
  2. What is a choropleth map?
  3. What is a cartogram?
  4. What are the advantages and disadvantages of these mapping techniques?

Learning objectives

In this activity, you will:

  1. Use the concept of quadrats to analyze a real dataset.
  2. Learn about a quadrat-based test for randomness in point patterns.
  3. Learn how to use the p-value of a statistical test to make a decision.
  4. Think about the distribution of events in a null landscape.
  5. Think about ways to decide whether a landscape is random.

Suggested reading

O’Sullivan D and Unwin D (2010) Geographic Information Analysis, 2nd Edition, Chapter 7. John Wiley & Sons: New Jersey.

Preliminaries

For this activity you will need the following:

It is good practice to clear the working space to make sure that you do not have extraneous items there when you begin your work. The command in R to clear the workspace is rm (for “remove”), followed by a list of items to be removed. To clear the workspace from all objects, do the following:

rm(list = ls())

Note that ls() lists all objects currently on the worspace.

Load the libraries you will use in this activity. In addition to tidyverse, you will need spatstat, a package designed for the analysis of point patterns (you can learn about spatstat here and here):

library(tidyverse)
package <U+393C><U+3E31>tidyverse<U+393C><U+3E32> was built under R version 3.4.3-- Attaching packages --------------------------------------------- tidyverse 1.2.1 --
v ggplot2 2.2.1     v purrr   0.2.4
v tibble  1.4.1     v dplyr   0.7.4
v tidyr   0.7.2     v stringr 1.2.0
v readr   1.1.1     v forcats 0.2.0
package <U+393C><U+3E31>ggplot2<U+393C><U+3E32> was built under R version 3.4.2package <U+393C><U+3E31>tibble<U+393C><U+3E32> was built under R version 3.4.3package <U+393C><U+3E31>tidyr<U+393C><U+3E32> was built under R version 3.4.3package <U+393C><U+3E31>purrr<U+393C><U+3E32> was built under R version 3.4.3package <U+393C><U+3E31>dplyr<U+393C><U+3E32> was built under R version 3.4.3package <U+393C><U+3E31>forcats<U+393C><U+3E32> was built under R version 3.4.3-- Conflicts ------------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(rgdal)
Loading required package: sp
rgdal: version: 1.2-11, (SVN revision 676)
 Geospatial Data Abstraction Library extensions to R successfully loaded
 Loaded GDAL runtime: GDAL 2.2.0, released 2017/04/28
 Path to GDAL shared files: C:/Users/Antonio/Documents/R/win-library/3.4/rgdal/gdal
 Loaded PROJ.4 runtime: Rel. 4.9.3, 15 August 2016, [PJ_VERSION: 493]
 Path to PROJ.4 shared files: C:/Users/Antonio/Documents/R/win-library/3.4/rgdal/proj
 Linking to sp version: 1.2-5 
library(broom)
library(cartogram)
package <U+393C><U+3E31>cartogram<U+393C><U+3E32> was built under R version 3.4.3
library(plotly)
package <U+393C><U+3E31>plotly<U+393C><U+3E32> was built under R version 3.4.3
Attaching package: <U+393C><U+3E31>plotly<U+393C><U+3E32>

The following object is masked from <U+393C><U+3E31>package:ggplot2<U+393C><U+3E32>:

    last_plot

The following object is masked from <U+393C><U+3E31>package:stats<U+393C><U+3E32>:

    filter

The following object is masked from <U+393C><U+3E31>package:graphics<U+393C><U+3E32>:

    layout

In the practice that preceded this activity, you learned about the area data and visualization techniques for area data.

Begin by loading the data that you will use in this activity:

Hamilton_CT <- readOGR(".", layer = "Hamilton CMA CT", integer64 = "allow.loss")
OGR data source with driver: ESRI Shapefile 
Source: ".", layer: "Hamilton CMA CT"
with 188 features
It has 255 fields
Integer64 fields read as signed 32-bit integers:  ID POPULATION PRIVATE_DW OCCUPIED_D ALL_AGES AGE_4 AGE_5_TO_9 AGE_10_TO_ AGE_15_TO_ AGE_15 AGE_16 AGE_17 AGE_18 AGE_19 AGE_20_TO_ AGE_25_TO_ AGE_30_TO_ AGE_35_TO_ AGE_40_TO_ AGE_45_TO_ AGE_50_TO_ AGE_55_TO_ AGE_60_TO_ AGE_65_TO_ AGE_70_TO_ AGE_75_TO_ AGE_80_TO_ AGE_85 MEDIAN_AGE MALE_ALL_A MALE_4 MALE_5_TO_ MALE_10_TO MALE_15_TO MALE_15 MALE_16 MALE_17 MALE_18 MALE_19 MALE_20_TO MALE_25_TO MALE_30_TO MALE_35_TO MALE_40_TO MALE_45_TO MALE_50_TO MALE_55_TO MALE_60_TO MALE_65_TO MALE_70_TO MALE_75_TO MALE_80_TO MALE_85 MALE_MEDIA FEMALE_ALL FEMALE_4 FEMALE_5_T FEMALE_10_ FEMALE_15_ FEMALE_15 FEMALE_16 FEMALE_17 FEMALE_18 FEMALE_19 FEMALE_20_ FEMALE_25_ FEMALE_30_ FEMALE_35_ FEMALE_40_ FEMALE_45_ FEMALE_50_ FEMALE_55_ FEMALE_60_ FEMALE_65_ FEMALE_70_ FEMALE_75_ FEMALE_80_ FEMALE_85 FEMALE_MED MARRIED_AG MARRIED_OR MARRIED COMMON_LAW UNMARRIED SINGLE SEPARATED DIVORCED WIDOWED MARRIED_A1 MARRIED_O1 MARRIED_M COMMON_LA1 UNMARRIED_ SINGLE_M SEPARATED_ DIVORCED_M WIDOWED_M MARRIED_A2 MARRIED_O2 MARRIED_F COMMON_LA2 UNMARRIED1 SINGLE_F SEPARATED1 DIVORCED_F WIDOWED_F FAMILIES_I FAMILY_SIZ FAMILY_SI1 FAMILY_SI2 FAMILY_SI3 COUPLE_FAM COUPLE_MAR COUPLE_MA1 COUPLE_MA2 COUPLE_MA3 COUPLE_MA4 COUPLE_MA5 COUPLE_COM COUPLE_CO1 COUPLE_CO2 COUPLE_CO3 COUPLE_CO4 COUPLE_CO5 SINGLE_PAR SINGLE_PA1 SINGLE_PA2 SINGLE_PA3 SINGLE_PA4 SINGLE_PA5 SINGLE_PA6 SINGLE_PA7 SINGLE_PA8 CHILDREN_F CHILDREN_1 CHILDREN_2 CHILDREN_3 CHILDREN_4 CHILDREN_5 POPULATIO1 POPULATIO2 POPULATIO3 POPULATIO4 POPULATIO5 POPULATIO6 POPULATIO7 POPULATIO8 POPULATIO9 POPULATI10 POPULATI11 POPULATI12 PRIVATE_HO PRIVATE_HH PRIVATE_H1 PRIVATE_H2 PRIVATE_H3 PRIVATE_H4 PRIVATE_H5 PRIVATE_H6 PRIVATE_H7 PRIVATE_H8 PRIVATE_H9 PRIVATE_10 PRIVATE_11 PRIVATE_12 PRIVATE_13 PRIVATE_14 PRIVATE_15 OCC_PRIVAT OCC_PRIVA1 OCC_PRIVA2 OCC_PRIVA3 OCC_PRIVA4 OCC_PRIVA5 OCC_PRIVA6 OCC_PRIVA7 OCC_PRIVA8 OCC_PRIVA9 PRIVATE_16 PRIVATE_17 PRIVATE_18 PRIVATE_19 PRIVATE_20 PRIVATE_21 PRIVATE_22 PRIVATE_23 NATIVE_LAN NATIVE_LA1 NATIVE_LA2 NATIVE_LA3 NATIVE_LA4 NATIVE_LA5 NATIVE_LA6 NATIVE_LA7 NATIVE_LA8 NATIVE_LA9 NATIVE_L10 NATIVE_L11 NATIVE_L12 NATIVE_L13 NATIVE_L14 NATIVE_L15 NATIVE_L16 NATIVE_L17 NATIVE_L18 NATIVE_L19 NATIVE_L20 NATIVE_L21 NATIVE_L22 NATIVE_L23 NATIVE_L24 NATIVE_L25 NATIVE_L26 NATIVE_L27 NATIVE_L28 NATIVE_L29 NATIVE_L30 NATIVE_L31 NATIVE_L32 NATIVE_L33 NATIVE_L34 NATIVE_L35 NATIVE_L36 NATIVE_L37 NATIVE_L38 NATIVE_L39 NATIVE_L40 NATIVE_L41 NATIVE_L42 NATIVE_L43 NATIVE_L44 NATIVE_L45 NATIVE_L46 NATIVE_L47 NATIVE_L48 NATIVE_L49 NATIVE_L50 NATIVE_L51 NATIVE_L52 NATIVE_L53 NATIVE_L54 NATIVE_L55 NATIVE_L56 NATIVE_L57 NATIVE_L58 NATIVE_L59 

You can obtain new (calculated) variables as follows. For instance, to obtain the proportion of residents who are between 20 and 34 years old, and between 35 and 49:

Hamilton_CT@data <- dplyr::transmute(Hamilton_CT@data, AREA = AREA, TRACT = TRACT,
                                     POPULATION = POPULATION,
                                     POP20to34 = (AGE_20_TO_ + AGE_25_TO_ + AGE_30_TO_),
                                     Prop20to34 = POP20to34/POPULATION, 
                                     POP35to49 = (AGE_35_TO_ + AGE_40_TO_ + AGE_45_TO_),
                                     Prop35to49 = POP35to49/POPULATION, 
                                     POP50to64 = (AGE_50_TO_ + AGE_55_TO_ + AGE_60_TO_),
                                     Prop50to64 = POP50to64/POPULATION,
                                     POP65Plus = (AGE_65_TO_ + AGE_70_TO_ + AGE_75_TO_ + AGE_80_TO_ + AGE_85),
                                     Prop65Plus = POP65Plus/POPULATION)

This is a SpatialPolygonDataFrame. Convert to a dataframe (“tidy” it) for plotting using ggplot2:

Hamilton_CT.t <- tidy(Hamilton_CT, region = "TRACT")
Hamilton_CT.t <- rename(Hamilton_CT.t, TRACT = id)

Rejoin the data:

Hamilton_CT.t <- left_join(Hamilton_CT.t, Hamilton_CT@data, by = "TRACT")
Column `TRACT` joining character vector and factor, coercing into character vector

Activity

  1. Create choropleth maps for the proportion of the population who are 20 to 34 years old, 35 to 49 years old, 50 to 65 years old, and 65 and older.
ggplot() + 
  geom_polygon(data = Hamilton_CT.t, aes(x = long, y = lat, group = group, fill = cut_number(Prop20to34, 5)), color = "white") + 
  coord_fixed() +
  scale_fill_brewer(palette = "YlOrRd") +
  labs(fill = "Prop Age 20 to 34")

ggplot() + 
  geom_polygon(data = Hamilton_CT.t, aes(x = long, y = lat, group = group, fill = cut_number(Prop35to49, 5)), color = "white") + 
  coord_fixed() +
  scale_fill_brewer(palette = "YlOrRd") +
  labs(fill = "Prop Age 35 to 49")

ggplot() + 
  geom_polygon(data = Hamilton_CT.t, aes(x = long, y = lat, group = group, fill = cut_number(Prop50to64, 5)), color = "white") + 
  coord_fixed() +
  scale_fill_brewer(palette = "YlOrRd") +
  labs(fill = "Prop Age 50 to 64")

ggplot() + 
  geom_polygon(data = Hamilton_CT.t, aes(x = long, y = lat, group = group, fill = cut_number(Prop65Plus, 5)), color = "white") + 
  coord_fixed() +
  scale_fill_brewer(palette = "YlOrRd") +
  labs(fill = "Prop Age 65+")

  1. Show your maps to a fellow student. What patterns do you notice in the distribution of age in Hamilton?

  2. Devise a rule to decide whether the pattern observed in a choropleth map is random.

Bonus

Create cartograms of the same variables above. Since the cartograms are created based on the SpatialPolygonsDataFrame:

Prop20to34.cartogram <- cartogram(shp = Hamilton_CT, weight = "POPULATION")
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 1: 5.94063097656517
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 2: 4.22282836609772
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 3: 3.24121918122005
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 4: 2.70487592121738
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 5: 2.44050500280525
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 6: 2.28238579460187
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 7: 2.14591026585647
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 8: 1.95255176465899
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 9: 1.8186943555214
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 10: 1.73775203417466
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 11: 1.64845060853967
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 12: 1.45162213155545
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 13: 1.37178691507706
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 14: 1.32738198642848
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 15: 1.29727221750122
Prop35to49.cartogram <- cartogram(shp = Hamilton_CT, weight = "POPULATION")
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 1: 5.94063097656517
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 2: 4.22282836609772
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 3: 3.24121918122005
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 4: 2.70487592121738
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 5: 2.44050500280525
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 6: 2.28238579460187
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 7: 2.14591026585647
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 8: 1.95255176465899
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 9: 1.8186943555214
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 10: 1.73775203417466
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 11: 1.64845060853967
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 12: 1.45162213155545
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 13: 1.37178691507706
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 14: 1.32738198642848
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 15: 1.29727221750122
Prop50to64.cartogram <- cartogram(shp = Hamilton_CT, weight = "POPULATION")
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 1: 5.94063097656517
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 2: 4.22282836609772
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 3: 3.24121918122005
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 4: 2.70487592121738
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 5: 2.44050500280525
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 6: 2.28238579460187
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 7: 2.14591026585647
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 8: 1.95255176465899
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 9: 1.8186943555214
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 10: 1.73775203417466
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 11: 1.64845060853967
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 12: 1.45162213155545
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 13: 1.37178691507706
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 14: 1.32738198642848
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 15: 1.29727221750122
Prop65Plus.cartogram <- cartogram(shp = Hamilton_CT, weight = "POPULATION")
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 1: 5.94063097656517
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 2: 4.22282836609772
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 3: 3.24121918122005
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 4: 2.70487592121738
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 5: 2.44050500280525
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 6: 2.28238579460187
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 7: 2.14591026585647
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 8: 1.95255176465899
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 9: 1.8186943555214
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 10: 1.73775203417466
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 11: 1.64845060853967
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 12: 1.45162213155545
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 13: 1.37178691507706
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 14: 1.32738198642848
Spatial object is not projected; GEOS expects planar coordinatesSpatial object is not projected; GEOS expects planar coordinatesMean size error for iteration 15: 1.29727221750122

Tidy and restore the data:

Prop20to34.cartogram.t <- tidy(Prop20to34.cartogram, region = "TRACT")
Prop20to34.cartogram.t <- rename(Prop20to34.cartogram.t, TRACT = id)
Prop20to34.cartogram.t <- left_join(Prop20to34.cartogram.t, select(Prop20to34.cartogram@data, TRACT, Prop20to34), by = "TRACT")
Column `TRACT` joining character vector and factor, coercing into character vector
Prop20to34.cartogram.t <- rename(Prop20to34.cartogram.t, Proportion = Prop20to34)
Prop35to49.cartogram.t <- tidy(Prop35to49.cartogram, region = "TRACT")
Prop35to49.cartogram.t <- rename(Prop35to49.cartogram.t, TRACT = id)
Prop35to49.cartogram.t <- left_join(Prop35to49.cartogram.t, select(Prop35to49.cartogram@data, TRACT, Prop35to49), by = "TRACT")
Column `TRACT` joining character vector and factor, coercing into character vector
Prop35to49.cartogram.t <- rename(Prop35to49.cartogram.t, Proportion = Prop35to49)
Prop50to64.cartogram.t <- tidy(Prop50to64.cartogram, region = "TRACT")
Prop50to64.cartogram.t <- rename(Prop50to64.cartogram.t, TRACT = id)
Prop50to64.cartogram.t <- left_join(Prop50to64.cartogram.t, select(Prop50to64.cartogram@data, TRACT, Prop50to64), by = "TRACT")
Column `TRACT` joining character vector and factor, coercing into character vector
Prop50to64.cartogram.t <- rename(Prop50to64.cartogram.t, Proportion = Prop50to64)
Prop65Plus.cartogram.t <- tidy(Prop65Plus.cartogram, region = "TRACT")
Prop65Plus.cartogram.t <- rename(Prop65Plus.cartogram.t, TRACT = id)
Prop65Plus.cartogram.t <- left_join(Prop65Plus.cartogram.t, select(Prop65Plus.cartogram@data, TRACT, Prop65Plus), by = "TRACT")
Column `TRACT` joining character vector and factor, coercing into character vector
Prop65Plus.cartogram.t <- rename(Prop65Plus.cartogram.t, Proportion = Prop65Plus)

Stack all cartograms into a single dataframe, add factor for frames:

Cartograms <- rbind(data.frame(Prop20to34.cartogram.t, factor = "Age 20 to 34"),
                    data.frame(Prop35to49.cartogram.t, factor = "Age 35 to 49"),
                    data.frame(Prop50to64.cartogram.t, factor = "Age 50 to 64"),
                    data.frame(Prop65Plus.cartogram.t, factor = "Age 65+"))

Create plot with frames:

Cartograms.plot <- ggplot(Cartograms, aes(x= long, y = lat, group = group, fill = cut_number(Proportion, 5))) + 
  geom_polygon(aes(frame = factor), color = "white") +
  scale_fill_brewer(palette = "YlOrRd") +
  coord_fixed() +
  theme(legend.position = "bottom") +
  labs(fill = "Proportion")
Ignoring unknown aesthetics: frame

Plot:

ggplotly(Cartograms.plot)
We recommend that you use the dev version of ggplot2 with `ggplotly()`
Install it with: `devtools::install_github('hadley/ggplot2')`

Try rectangular cartograms:

library(recmap)
package <U+393C><U+3E31>recmap<U+393C><U+3E32> was built under R version 3.4.3Loading required package: GA
package <U+393C><U+3E31>GA<U+393C><U+3E32> was built under R version 3.4.3Loading required package: foreach
foreach: simple, scalable parallel programming from Revolution Analytics
Use Revolution R for scalability, fault tolerance and more.
http://www.revolutionanalytics.com

Attaching package: <U+393C><U+3E31>foreach<U+393C><U+3E32>

The following objects are masked from <U+393C><U+3E31>package:purrr<U+393C><U+3E32>:

    accumulate, when

Loading required package: iterators
  ____    _    
 / ___|  / \     Genetic 
| |  _  / _ \    Algorithms
| |_| |/ ___ \   
 \____/_/   \_\  version 3.0.2
Type 'citation("GA")' for citing this R package in publications.
Loading required package: Rcpp
Package 'recmap' version 0.5.24

Rectangular algorithms require the centroids of the zones, which can be obtained by means of sp::coordinates

xy_centroids <- coordinates(Hamilton_CT)

Create a frame for the rectangular cartograms:

rec_frame <- data.frame(x = xy_centroids[,1], 
           y = xy_centroids[,2],
           dx = sqrt(Hamilton_CT$AREA) / 2 / (0.7 * 60 * cos(xy_centroids[,2] * pi / 180)),
           dy = sqrt(Hamilton_CT$AREA) / 2 / (0.7 * 60)) 

Generate the input for the recmap function. This is the frame for the cartograms rec_frame and a variable z:

POP.rec <- data.frame(rec_frame, z = Hamilton_CT$POPULATION + 1, name = Hamilton_CT$TRACT)
head(POP.rec)
POP.rec.cartogram <- recmap(POP.rec)
5370140.04 could not be placed on the first attempt;5370140.03 could not be placed on the first attempt;5370084.04 could not be placed on the first attempt;5370086.00 could not be placed on the first attempt;5370301.00 could not be placed on the first attempt;5370303.01 could not be placed on the first attempt;5370303.02 could not be placed on the first attempt;5370302.00 could not be placed on the first attempt;5370300.00 could not be placed on the first attempt;5370085.03 could not be placed on the first attempt;5370085.02 could not be placed on the first attempt;5370085.01 could not be placed on the first attempt;5370084.05 could not be placed on the first attempt;5370084.03 could not be placed on the first attempt;5370084.02 could not be placed on the first attempt;5370084.01 could not be placed on the first attempt;5370072.04 could not be placed on the first attempt;
plot(POP.rec.cartogram)

ggplot(data = POP.rec.cartogram) + geom_rect(aes(xmin = x - dx, xmax = x + dx, ymin = y - dy, ymax = y + dy)) + coord_fixed()

Cartograms.rec <- rbind(data.frame(POP.rec.cartogram,
                                   Proportion = Hamilton_CT$Prop20to34,
                                   factor = "Age 20 to 34"),
                        data.frame(POP.rec.cartogram,
                                   Proportion = Hamilton_CT$Prop35to49,
                                   factor = "Age 35 to 49"),
                        data.frame(POP.rec.cartogram,
                                   Proportion = Hamilton_CT$Prop50to64,
                                   factor = "Age 50 to 64"),
                        data.frame(POP.rec.cartogram,
                                   Proportion = Hamilton_CT$Prop65Plus,
                                   factor = "Age 65+"))

Create plot with frames:

Cartograms.rec.plot <- ggplot(Cartograms.rec, aes(xmin = x - dx, xmax = x + dx, ymin = y - dy, ymax = y + dy, fill = cut_number(Proportion, 5))) + 
  geom_rect(aes(frame = factor)) +
  scale_fill_brewer(palette = "YlOrRd") +
  coord_fixed() +
  theme(legend.position = "bottom") +
  labs(fill = "Proportion")
Ignoring unknown aesthetics: frame

Plot:

plot <- Cartograms.rec.plot %>% animation_opts(frame = 1000, transition = 1000, easing = "elastic")
ggplotly(plot)
We recommend that you use the dev version of ggplot2 with `ggplotly()`
Install it with: `devtools::install_github('hadley/ggplot2')`
LS0tDQp0aXRsZTogIjA0IFNlc3Npb24gNDogUG9pbnQgUGF0dGVybiBBbmFseXNpcyBJIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KI1ByYWN0aWNlIHF1ZXN0aW9ucw0KDQpBbnN3ZXIgdGhlIGZvbGxvd2luZyBxdWVzdGlvbnM6DQoNCjEuIFdoYXQgaXMgYSBrZXkgZGlmZmVyZW5jZSBiZXR3ZWVuIGFyZWEgZGF0YSBhbmQgcG9pbnQgZGF0YT8NCjIuIFdoYXQgaXMgYSBjaG9yb3BsZXRoIG1hcD8NCjMuIFdoYXQgaXMgYSBjYXJ0b2dyYW0/DQo0LiBXaGF0IGFyZSB0aGUgYWR2YW50YWdlcyBhbmQgZGlzYWR2YW50YWdlcyBvZiB0aGVzZSBtYXBwaW5nIHRlY2huaXF1ZXM/DQoNCiNMZWFybmluZyBvYmplY3RpdmVzDQoNCkluIHRoaXMgYWN0aXZpdHksIHlvdSB3aWxsOg0KDQoxLiBVc2UgdGhlIGNvbmNlcHQgb2YgcXVhZHJhdHMgdG8gYW5hbHl6ZSBhIHJlYWwgZGF0YXNldC4NCjIuIExlYXJuIGFib3V0IGEgcXVhZHJhdC1iYXNlZCB0ZXN0IGZvciByYW5kb21uZXNzIGluIHBvaW50IHBhdHRlcm5zLg0KMy4gTGVhcm4gaG93IHRvIHVzZSB0aGUgcC12YWx1ZSBvZiBhIHN0YXRpc3RpY2FsIHRlc3QgdG8gbWFrZSBhIGRlY2lzaW9uLg0KNC4gVGhpbmsgYWJvdXQgdGhlIGRpc3RyaWJ1dGlvbiBvZiBldmVudHMgaW4gYSBudWxsIGxhbmRzY2FwZS4NCjUuIFRoaW5rIGFib3V0IHdheXMgdG8gZGVjaWRlIHdoZXRoZXIgYSBsYW5kc2NhcGUgaXMgcmFuZG9tLg0KDQojU3VnZ2VzdGVkIHJlYWRpbmcNCg0KTydTdWxsaXZhbiBEIGFuZCBVbndpbiBEICgyMDEwKSBHZW9ncmFwaGljIEluZm9ybWF0aW9uIEFuYWx5c2lzLCAybmQgRWRpdGlvbiwgQ2hhcHRlciA3LiBKb2huIFdpbGV5ICYgU29uczogTmV3IEplcnNleS4NCg0KI1ByZWxpbWluYXJpZXMNCg0KRm9yIHRoaXMgYWN0aXZpdHkgeW91IHdpbGwgbmVlZCB0aGUgZm9sbG93aW5nOg0KDQoqIFRoaXMgUiBtYXJrZG93biBub3RlYm9vay4NCiogQSBkYXRhc2V0IGNhbGxlZCBgVG9yb250byBCdXNpbmVzcyBQb2ludHMuUkRhdGFgLg0KDQpJdCBpcyBnb29kIHByYWN0aWNlIHRvIGNsZWFyIHRoZSB3b3JraW5nIHNwYWNlIHRvIG1ha2Ugc3VyZSB0aGF0IHlvdSBkbyBub3QgaGF2ZSBleHRyYW5lb3VzIGl0ZW1zIHRoZXJlIHdoZW4geW91IGJlZ2luIHlvdXIgd29yay4gVGhlIGNvbW1hbmQgaW4gUiB0byBjbGVhciB0aGUgd29ya3NwYWNlIGlzIGBybWAgKGZvciAicmVtb3ZlIiksIGZvbGxvd2VkIGJ5IGEgbGlzdCBvZiBpdGVtcyB0byBiZSByZW1vdmVkLiBUbyBjbGVhciB0aGUgd29ya3NwYWNlIGZyb20gX2FsbF8gb2JqZWN0cywgZG8gdGhlIGZvbGxvd2luZzoNCmBgYHtyfQ0Kcm0obGlzdCA9IGxzKCkpDQpgYGANCg0KTm90ZSB0aGF0IGBscygpYCBsaXN0cyBhbGwgb2JqZWN0cyBjdXJyZW50bHkgb24gdGhlIHdvcnNwYWNlLg0KDQpMb2FkIHRoZSBsaWJyYXJpZXMgeW91IHdpbGwgdXNlIGluIHRoaXMgYWN0aXZpdHkuIEluIGFkZGl0aW9uIHRvIGB0aWR5dmVyc2VgLCB5b3Ugd2lsbCBuZWVkIGBzcGF0c3RhdGAsIGEgcGFja2FnZSBkZXNpZ25lZCBmb3IgdGhlIGFuYWx5c2lzIG9mIHBvaW50IHBhdHRlcm5zICh5b3UgY2FuIGxlYXJuIGFib3V0IGBzcGF0c3RhdGAgW2hlcmVdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9zcGF0c3RhdC92aWduZXR0ZXMvZ2V0c3RhcnQucGRmKSBhbmQgW2hlcmVdKGh0dHA6Ly9zcGF0c3RhdC5vcmcvcmVzb3VyY2VzL3NwYXRzdGF0SlNTcGFwZXIucGRmKSk6DQpgYGB7cn0NCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShyZ2RhbCkNCmxpYnJhcnkoYnJvb20pDQpsaWJyYXJ5KGNhcnRvZ3JhbSkNCmxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCkluIHRoZSBwcmFjdGljZSB0aGF0IHByZWNlZGVkIHRoaXMgYWN0aXZpdHksIHlvdSBsZWFybmVkIGFib3V0IHRoZSBhcmVhIGRhdGEgYW5kIHZpc3VhbGl6YXRpb24gdGVjaG5pcXVlcyBmb3IgYXJlYSBkYXRhLg0KDQpCZWdpbiBieSBsb2FkaW5nIHRoZSBkYXRhIHRoYXQgeW91IHdpbGwgdXNlIGluIHRoaXMgYWN0aXZpdHk6DQpgYGB7cn0NCkhhbWlsdG9uX0NUIDwtIHJlYWRPR1IoIi4iLCBsYXllciA9ICJIYW1pbHRvbiBDTUEgQ1QiLCBpbnRlZ2VyNjQgPSAiYWxsb3cubG9zcyIpDQpgYGANCg0KWW91IGNhbiBvYnRhaW4gbmV3IChjYWxjdWxhdGVkKSB2YXJpYWJsZXMgYXMgZm9sbG93cy4gRm9yIGluc3RhbmNlLCB0byBvYnRhaW4gdGhlIHByb3BvcnRpb24gb2YgcmVzaWRlbnRzIHdobyBhcmUgYmV0d2VlbiAyMCBhbmQgMzQgeWVhcnMgb2xkLCBhbmQgYmV0d2VlbiAzNSBhbmQgNDk6DQpgYGB7cn0NCkhhbWlsdG9uX0NUQGRhdGEgPC0gZHBseXI6OnRyYW5zbXV0ZShIYW1pbHRvbl9DVEBkYXRhLCBBUkVBID0gQVJFQSwgVFJBQ1QgPSBUUkFDVCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQT1BVTEFUSU9OID0gUE9QVUxBVElPTiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQT1AyMHRvMzQgPSAoQUdFXzIwX1RPXyArIEFHRV8yNV9UT18gKyBBR0VfMzBfVE9fKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQcm9wMjB0bzM0ID0gUE9QMjB0bzM0L1BPUFVMQVRJT04sIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBPUDM1dG80OSA9IChBR0VfMzVfVE9fICsgQUdFXzQwX1RPXyArIEFHRV80NV9UT18pLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFByb3AzNXRvNDkgPSBQT1AzNXRvNDkvUE9QVUxBVElPTiwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUE9QNTB0bzY0ID0gKEFHRV81MF9UT18gKyBBR0VfNTVfVE9fICsgQUdFXzYwX1RPXyksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUHJvcDUwdG82NCA9IFBPUDUwdG82NC9QT1BVTEFUSU9OLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBPUDY1UGx1cyA9IChBR0VfNjVfVE9fICsgQUdFXzcwX1RPXyArIEFHRV83NV9UT18gKyBBR0VfODBfVE9fICsgQUdFXzg1KSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQcm9wNjVQbHVzID0gUE9QNjVQbHVzL1BPUFVMQVRJT04pDQpgYGANCg0KVGhpcyBpcyBhIGBTcGF0aWFsUG9seWdvbkRhdGFGcmFtZWAuIENvbnZlcnQgdG8gYSBkYXRhZnJhbWUgKCJ0aWR5IiBpdCkgZm9yIHBsb3R0aW5nIHVzaW5nIGBnZ3Bsb3QyYDoNCmBgYHtyfQ0KSGFtaWx0b25fQ1QudCA8LSB0aWR5KEhhbWlsdG9uX0NULCByZWdpb24gPSAiVFJBQ1QiKQ0KSGFtaWx0b25fQ1QudCA8LSByZW5hbWUoSGFtaWx0b25fQ1QudCwgVFJBQ1QgPSBpZCkNCmBgYA0KDQpSZWpvaW4gdGhlIGRhdGE6DQpgYGB7cn0NCkhhbWlsdG9uX0NULnQgPC0gbGVmdF9qb2luKEhhbWlsdG9uX0NULnQsIEhhbWlsdG9uX0NUQGRhdGEsIGJ5ID0gIlRSQUNUIikNCmBgYA0KDQojQWN0aXZpdHkNCg0KMS4gQ3JlYXRlIGNob3JvcGxldGggbWFwcyBmb3IgdGhlIHByb3BvcnRpb24gb2YgdGhlIHBvcHVsYXRpb24gd2hvIGFyZSAyMCB0byAzNCB5ZWFycyBvbGQsIDM1IHRvIDQ5IHllYXJzIG9sZCwgNTAgdG8gNjUgeWVhcnMgb2xkLCBhbmQgNjUgYW5kIG9sZGVyLiANCg0KYGBge3J9DQpnZ3Bsb3QoKSArIA0KICBnZW9tX3BvbHlnb24oZGF0YSA9IEhhbWlsdG9uX0NULnQsIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IGN1dF9udW1iZXIoUHJvcDIwdG8zNCwgNSkpLCBjb2xvciA9ICJ3aGl0ZSIpICsgDQogIGNvb3JkX2ZpeGVkKCkgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIllsT3JSZCIpICsNCiAgbGFicyhmaWxsID0gIlByb3AgQWdlIDIwIHRvIDM0IikNCg0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KCkgKyANCiAgZ2VvbV9wb2x5Z29uKGRhdGEgPSBIYW1pbHRvbl9DVC50LCBhZXMoeCA9IGxvbmcsIHkgPSBsYXQsIGdyb3VwID0gZ3JvdXAsIGZpbGwgPSBjdXRfbnVtYmVyKFByb3AzNXRvNDksIDUpKSwgY29sb3IgPSAid2hpdGUiKSArIA0KICBjb29yZF9maXhlZCgpICsNCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJZbE9yUmQiKSArDQogIGxhYnMoZmlsbCA9ICJQcm9wIEFnZSAzNSB0byA0OSIpDQoNCmBgYA0KDQpgYGB7cn0NCmdncGxvdCgpICsgDQogIGdlb21fcG9seWdvbihkYXRhID0gSGFtaWx0b25fQ1QudCwgYWVzKHggPSBsb25nLCB5ID0gbGF0LCBncm91cCA9IGdyb3VwLCBmaWxsID0gY3V0X251bWJlcihQcm9wNTB0bzY0LCA1KSksIGNvbG9yID0gIndoaXRlIikgKyANCiAgY29vcmRfZml4ZWQoKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiWWxPclJkIikgKw0KICBsYWJzKGZpbGwgPSAiUHJvcCBBZ2UgNTAgdG8gNjQiKQ0KDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoKSArIA0KICBnZW9tX3BvbHlnb24oZGF0YSA9IEhhbWlsdG9uX0NULnQsIGFlcyh4ID0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IGN1dF9udW1iZXIoUHJvcDY1UGx1cywgNSkpLCBjb2xvciA9ICJ3aGl0ZSIpICsgDQogIGNvb3JkX2ZpeGVkKCkgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIllsT3JSZCIpICsNCiAgbGFicyhmaWxsID0gIlByb3AgQWdlIDY1KyIpDQoNCmBgYA0KDQoyLiBTaG93IHlvdXIgbWFwcyB0byBhIGZlbGxvdyBzdHVkZW50LiBXaGF0IHBhdHRlcm5zIGRvIHlvdSBub3RpY2UgaW4gdGhlIGRpc3RyaWJ1dGlvbiBvZiBhZ2UgaW4gSGFtaWx0b24/DQoNCjMuIERldmlzZSBhIHJ1bGUgdG8gZGVjaWRlIHdoZXRoZXIgdGhlIHBhdHRlcm4gb2JzZXJ2ZWQgaW4gYSBjaG9yb3BsZXRoIG1hcCBpcyByYW5kb20uDQoNCiMgQm9udXMNCg0KQ3JlYXRlIGNhcnRvZ3JhbXMgb2YgdGhlIHNhbWUgdmFyaWFibGVzIGFib3ZlLiBTaW5jZSB0aGUgY2FydG9ncmFtcyBhcmUgY3JlYXRlZCBiYXNlZCBvbiB0aGUgYFNwYXRpYWxQb2x5Z29uc0RhdGFGcmFtZWA6DQpgYGB7cn0NClByb3AyMHRvMzQuY2FydG9ncmFtIDwtIGNhcnRvZ3JhbShzaHAgPSBIYW1pbHRvbl9DVCwgd2VpZ2h0ID0gIlBPUFVMQVRJT04iKQ0KUHJvcDM1dG80OS5jYXJ0b2dyYW0gPC0gY2FydG9ncmFtKHNocCA9IEhhbWlsdG9uX0NULCB3ZWlnaHQgPSAiUE9QVUxBVElPTiIpDQpQcm9wNTB0bzY0LmNhcnRvZ3JhbSA8LSBjYXJ0b2dyYW0oc2hwID0gSGFtaWx0b25fQ1QsIHdlaWdodCA9ICJQT1BVTEFUSU9OIikNClByb3A2NVBsdXMuY2FydG9ncmFtIDwtIGNhcnRvZ3JhbShzaHAgPSBIYW1pbHRvbl9DVCwgd2VpZ2h0ID0gIlBPUFVMQVRJT04iKQ0KYGBgDQoNClRpZHkgYW5kIHJlc3RvcmUgdGhlIGRhdGE6DQpgYGB7cn0NClByb3AyMHRvMzQuY2FydG9ncmFtLnQgPC0gdGlkeShQcm9wMjB0bzM0LmNhcnRvZ3JhbSwgcmVnaW9uID0gIlRSQUNUIikNClByb3AyMHRvMzQuY2FydG9ncmFtLnQgPC0gcmVuYW1lKFByb3AyMHRvMzQuY2FydG9ncmFtLnQsIFRSQUNUID0gaWQpDQpQcm9wMjB0bzM0LmNhcnRvZ3JhbS50IDwtIGxlZnRfam9pbihQcm9wMjB0bzM0LmNhcnRvZ3JhbS50LCBzZWxlY3QoUHJvcDIwdG8zNC5jYXJ0b2dyYW1AZGF0YSwgVFJBQ1QsIFByb3AyMHRvMzQpLCBieSA9ICJUUkFDVCIpDQpQcm9wMjB0bzM0LmNhcnRvZ3JhbS50IDwtIHJlbmFtZShQcm9wMjB0bzM0LmNhcnRvZ3JhbS50LCBQcm9wb3J0aW9uID0gUHJvcDIwdG8zNCkNCg0KUHJvcDM1dG80OS5jYXJ0b2dyYW0udCA8LSB0aWR5KFByb3AzNXRvNDkuY2FydG9ncmFtLCByZWdpb24gPSAiVFJBQ1QiKQ0KUHJvcDM1dG80OS5jYXJ0b2dyYW0udCA8LSByZW5hbWUoUHJvcDM1dG80OS5jYXJ0b2dyYW0udCwgVFJBQ1QgPSBpZCkNClByb3AzNXRvNDkuY2FydG9ncmFtLnQgPC0gbGVmdF9qb2luKFByb3AzNXRvNDkuY2FydG9ncmFtLnQsIHNlbGVjdChQcm9wMzV0bzQ5LmNhcnRvZ3JhbUBkYXRhLCBUUkFDVCwgUHJvcDM1dG80OSksIGJ5ID0gIlRSQUNUIikNClByb3AzNXRvNDkuY2FydG9ncmFtLnQgPC0gcmVuYW1lKFByb3AzNXRvNDkuY2FydG9ncmFtLnQsIFByb3BvcnRpb24gPSBQcm9wMzV0bzQ5KQ0KDQpQcm9wNTB0bzY0LmNhcnRvZ3JhbS50IDwtIHRpZHkoUHJvcDUwdG82NC5jYXJ0b2dyYW0sIHJlZ2lvbiA9ICJUUkFDVCIpDQpQcm9wNTB0bzY0LmNhcnRvZ3JhbS50IDwtIHJlbmFtZShQcm9wNTB0bzY0LmNhcnRvZ3JhbS50LCBUUkFDVCA9IGlkKQ0KUHJvcDUwdG82NC5jYXJ0b2dyYW0udCA8LSBsZWZ0X2pvaW4oUHJvcDUwdG82NC5jYXJ0b2dyYW0udCwgc2VsZWN0KFByb3A1MHRvNjQuY2FydG9ncmFtQGRhdGEsIFRSQUNULCBQcm9wNTB0bzY0KSwgYnkgPSAiVFJBQ1QiKQ0KUHJvcDUwdG82NC5jYXJ0b2dyYW0udCA8LSByZW5hbWUoUHJvcDUwdG82NC5jYXJ0b2dyYW0udCwgUHJvcG9ydGlvbiA9IFByb3A1MHRvNjQpDQoNClByb3A2NVBsdXMuY2FydG9ncmFtLnQgPC0gdGlkeShQcm9wNjVQbHVzLmNhcnRvZ3JhbSwgcmVnaW9uID0gIlRSQUNUIikNClByb3A2NVBsdXMuY2FydG9ncmFtLnQgPC0gcmVuYW1lKFByb3A2NVBsdXMuY2FydG9ncmFtLnQsIFRSQUNUID0gaWQpDQpQcm9wNjVQbHVzLmNhcnRvZ3JhbS50IDwtIGxlZnRfam9pbihQcm9wNjVQbHVzLmNhcnRvZ3JhbS50LCBzZWxlY3QoUHJvcDY1UGx1cy5jYXJ0b2dyYW1AZGF0YSwgVFJBQ1QsIFByb3A2NVBsdXMpLCBieSA9ICJUUkFDVCIpDQpQcm9wNjVQbHVzLmNhcnRvZ3JhbS50IDwtIHJlbmFtZShQcm9wNjVQbHVzLmNhcnRvZ3JhbS50LCBQcm9wb3J0aW9uID0gUHJvcDY1UGx1cykNCmBgYA0KDQpTdGFjayBhbGwgY2FydG9ncmFtcyBpbnRvIGEgc2luZ2xlIGRhdGFmcmFtZSwgYWRkIGZhY3RvciBmb3IgZnJhbWVzOg0KYGBge3J9DQpDYXJ0b2dyYW1zIDwtIHJiaW5kKGRhdGEuZnJhbWUoUHJvcDIwdG8zNC5jYXJ0b2dyYW0udCwgZmFjdG9yID0gIkFnZSAyMCB0byAzNCIpLA0KICAgICAgICAgICAgICAgICAgICBkYXRhLmZyYW1lKFByb3AzNXRvNDkuY2FydG9ncmFtLnQsIGZhY3RvciA9ICJBZ2UgMzUgdG8gNDkiKSwNCiAgICAgICAgICAgICAgICAgICAgZGF0YS5mcmFtZShQcm9wNTB0bzY0LmNhcnRvZ3JhbS50LCBmYWN0b3IgPSAiQWdlIDUwIHRvIDY0IiksDQogICAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUoUHJvcDY1UGx1cy5jYXJ0b2dyYW0udCwgZmFjdG9yID0gIkFnZSA2NSsiKSkNCmBgYA0KDQpDcmVhdGUgcGxvdCB3aXRoIGZyYW1lczoNCmBgYHtyfQ0KQ2FydG9ncmFtcy5wbG90IDwtIGdncGxvdChDYXJ0b2dyYW1zLCBhZXMoeD0gbG9uZywgeSA9IGxhdCwgZ3JvdXAgPSBncm91cCwgZmlsbCA9IGN1dF9udW1iZXIoUHJvcG9ydGlvbiwgNSkpKSArIA0KICBnZW9tX3BvbHlnb24oYWVzKGZyYW1lID0gZmFjdG9yKSwgY29sb3IgPSAid2hpdGUiKSArDQogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiWWxPclJkIikgKw0KICBjb29yZF9maXhlZCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpICsNCiAgbGFicyhmaWxsID0gIlByb3BvcnRpb24iKQ0KYGBgDQoNClBsb3Q6DQpgYGB7cn0NCmdncGxvdGx5KENhcnRvZ3JhbXMucGxvdCkNCmBgYA0KDQpUcnkgcmVjdGFuZ3VsYXIgY2FydG9ncmFtczoNCmBgYHtyfQ0KbGlicmFyeShyZWNtYXApDQpgYGANCg0KUmVjdGFuZ3VsYXIgYWxnb3JpdGhtcyByZXF1aXJlIHRoZSBjZW50cm9pZHMgb2YgdGhlIHpvbmVzLCB3aGljaCBjYW4gYmUgb2J0YWluZWQgYnkgbWVhbnMgb2YgYHNwOjpjb29yZGluYXRlc2ANCmBgYHtyfQ0KeHlfY2VudHJvaWRzIDwtIGNvb3JkaW5hdGVzKEhhbWlsdG9uX0NUKQ0KYGBgDQoNCkNyZWF0ZSBhIGZyYW1lIGZvciB0aGUgcmVjdGFuZ3VsYXIgY2FydG9ncmFtczoNCmBgYHtyfQ0KcmVjX2ZyYW1lIDwtIGRhdGEuZnJhbWUoeCA9IHh5X2NlbnRyb2lkc1ssMV0sIA0KICAgICAgICAgICB5ID0geHlfY2VudHJvaWRzWywyXSwNCiAgICAgICAgICAgZHggPSBzcXJ0KEhhbWlsdG9uX0NUJEFSRUEpIC8gMiAvICgwLjcgKiA2MCAqIGNvcyh4eV9jZW50cm9pZHNbLDJdICogcGkgLyAxODApKSwNCiAgICAgICAgICAgZHkgPSBzcXJ0KEhhbWlsdG9uX0NUJEFSRUEpIC8gMiAvICgwLjcgKiA2MCkpIA0KYGBgDQoNCkdlbmVyYXRlIHRoZSBpbnB1dCBmb3IgdGhlIGByZWNtYXBgIGZ1bmN0aW9uLiBUaGlzIGlzIHRoZSBmcmFtZSBmb3IgdGhlIGNhcnRvZ3JhbXMgYHJlY19mcmFtZWAgYW5kIGEgdmFyaWFibGUgejoNCmBgYHtyfQ0KUE9QLnJlYyA8LSBkYXRhLmZyYW1lKHJlY19mcmFtZSwgeiA9IEhhbWlsdG9uX0NUJFBPUFVMQVRJT04gKyAxLCBuYW1lID0gSGFtaWx0b25fQ1QkVFJBQ1QpDQpoZWFkKFBPUC5yZWMpDQpgYGANCg0KYGBge3J9DQpQT1AucmVjLmNhcnRvZ3JhbSA8LSByZWNtYXAoUE9QLnJlYykNCmBgYA0KDQpgYGB7cn0NCnBsb3QoUE9QLnJlYy5jYXJ0b2dyYW0pDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IFBPUC5yZWMuY2FydG9ncmFtKSArIGdlb21fcmVjdChhZXMoeG1pbiA9IHggLSBkeCwgeG1heCA9IHggKyBkeCwgeW1pbiA9IHkgLSBkeSwgeW1heCA9IHkgKyBkeSkpICsgY29vcmRfZml4ZWQoKQ0KYGBgDQoNCmBgYHtyfQ0KQ2FydG9ncmFtcy5yZWMgPC0gcmJpbmQoZGF0YS5mcmFtZShQT1AucmVjLmNhcnRvZ3JhbSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUHJvcG9ydGlvbiA9IEhhbWlsdG9uX0NUJFByb3AyMHRvMzQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY3RvciA9ICJBZ2UgMjAgdG8gMzQiKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEuZnJhbWUoUE9QLnJlYy5jYXJ0b2dyYW0sDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFByb3BvcnRpb24gPSBIYW1pbHRvbl9DVCRQcm9wMzV0bzQ5LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWN0b3IgPSAiQWdlIDM1IHRvIDQ5IiksDQogICAgICAgICAgICAgICAgICAgICAgICBkYXRhLmZyYW1lKFBPUC5yZWMuY2FydG9ncmFtLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQcm9wb3J0aW9uID0gSGFtaWx0b25fQ1QkUHJvcDUwdG82NCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmFjdG9yID0gIkFnZSA1MCB0byA2NCIpLA0KICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5mcmFtZShQT1AucmVjLmNhcnRvZ3JhbSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUHJvcG9ydGlvbiA9IEhhbWlsdG9uX0NUJFByb3A2NVBsdXMsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY3RvciA9ICJBZ2UgNjUrIikpDQpgYGANCg0KQ3JlYXRlIHBsb3Qgd2l0aCBmcmFtZXM6DQpgYGB7cn0NCkNhcnRvZ3JhbXMucmVjLnBsb3QgPC0gZ2dwbG90KENhcnRvZ3JhbXMucmVjLCBhZXMoeG1pbiA9IHggLSBkeCwgeG1heCA9IHggKyBkeCwgeW1pbiA9IHkgLSBkeSwgeW1heCA9IHkgKyBkeSwgZmlsbCA9IGN1dF9udW1iZXIoUHJvcG9ydGlvbiwgNSkpKSArIA0KICBnZW9tX3JlY3QoYWVzKGZyYW1lID0gZmFjdG9yKSkgKw0KICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIllsT3JSZCIpICsNCiAgY29vcmRfZml4ZWQoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKSArDQogIGxhYnMoZmlsbCA9ICJQcm9wb3J0aW9uIikNCmBgYA0KDQpQbG90Og0KYGBge3J9DQpwbG90IDwtIENhcnRvZ3JhbXMucmVjLnBsb3QgJT4lIGFuaW1hdGlvbl9vcHRzKGZyYW1lID0gMTAwMCwgdHJhbnNpdGlvbiA9IDEwMDAsIGVhc2luZyA9ICJlbGFzdGljIikNCmdncGxvdGx5KHBsb3QpDQpgYGA=